package com.authentication;

import com.authentication.code.AuthenticationCodeRepository;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;

import static com.authentication.common.Constant.GRANTED_SCOPES;
import static org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_POST;

public class InMemoryAuthenticationManger implements AuthenticationManager {

    private final AuthenticationCodeRepository authenticationCodeRepository;

    public InMemoryAuthenticationManger(AuthenticationCodeRepository authenticationCodeRepository) {
        this.authenticationCodeRepository = authenticationCodeRepository;
    }

    @Override
    public Authentication authenticate(Authentication clientAuthentication) throws AuthenticationException {

        if (clientAuthentication instanceof OAuth2AuthorizationCodeRequestAuthenticationToken client) {

            Instant now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
            Instant expiredAt = LocalDateTime.now().plusMinutes(1).atZone(ZoneId.systemDefault()).toInstant();

            Authentication userAuthentication = SecurityContextHolder.getContext().getAuthentication();

            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();


            String[] grantedScopes = requestAttributes.getRequest().getParameterValues(GRANTED_SCOPES);

//          用户可以选择授予 client 的权限列表
//          将其临时存储,待client 通过 authorization code 换取 token 的时候
//            为 token 设置上 user 授予的 权限列表
            String code = authenticationCodeRepository.storageCode(userAuthentication,client,grantedScopes);

            OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(code, now, expiredAt);

            OAuth2AuthorizationCodeRequestAuthenticationToken oAuth2ClientAuthenticationToken = new OAuth2AuthorizationCodeRequestAuthenticationToken(
                    client.getAuthorizationUri(),
                    client.getClientId(),
                    clientAuthentication,
                    authorizationCode,
                    client.getRedirectUri(),
                    client.getState(),
                    new HashSet<>(Arrays.asList(grantedScopes))
            );
            oAuth2ClientAuthenticationToken.setAuthenticated(true);



            return oAuth2ClientAuthenticationToken;
        }
        return null;

    }
}
